/*
 * cache.c
 *
 *  Created on: Apr 17, 2012
 *      Author: kody
 */


#include "cache.h"
#include "dmcache.h"
#include "asscache.h"
extern cache_s L1Icache;
extern cache_s L1Dcache;
extern cache_s L2cache;
boolean initCaches()
{
	L1Icache.level=L1I;
	L1Dcache.level=L1D;
	L2cache.level=L2;
	if(L1_assoc == 1){
		if(!createDMCache(&L1Icache)){
			return FALSE;
		}
		if(!createDMCache(&L1Dcache)){
			return FALSE;
		}
	}
	else{
		if(!createAssCache(&L1Icache)){
			return FALSE;
		}
		if(!createAssCache(&L1Dcache)){
			return FALSE;
		}
	}
	if(L2_assoc == 1){
		if(!createDMCache(&L2cache)){
			return FALSE;
		}
	}
	else{
		if(!createAssCache(&L2cache)){
			return FALSE;
		}
	}
	return TRUE;
}

boolean deleteCaches()
{
	if(L1_assoc == 1){
		if(!deleteDMCache(&L1Icache)){
			return FALSE;
		}
		if(!deleteDMCache(&L1Dcache)){
			return FALSE;
		}
	}
	else{
		if(!deleteAssCache(&L1Icache)){
			return FALSE;
		}
		if(!createAssCache(&L1Dcache)){
			return FALSE;
		}
	}
	if(L2_assoc == 1){
		if(!deleteDMCache(&L2cache)){
			return FALSE;
		}
	}
	else{
		if(!deleteAssCache(&L2cache)){
			return FALSE;
		}
	}
	return TRUE;
}
boolean checkCache(cache_s* cache, uint32 reference, opcode isWrite, results_s* results)
{
	boolean retval=FALSE;
	uint32 assoc=0;
	switch(cache->level)
	{
		case L1I:
		case L1D:
			assoc = L1_assoc;
			break;
		case L2:
			assoc = L2_assoc;
			break;
		default:
			printf("Invalid level\n");
			break;
	}
	if (assoc == 1)
	{
		if(checkDMCache(cache,reference,isWrite) == TRUE)
		{
			results->hitCount[cache->level]++;
			results->accessTotal[cache->level]++;
			retval = TRUE;
		}
		else
		{
			results->missCount[cache->level]++;
			results->accessTotal[cache->level]++;
			retval = FALSE;
		}

	}
	else
	{
		if(checkAssCache(cache,reference, isWrite) == TRUE)
		{
			results->hitCount[cache->level]++;
			results->accessTotal[cache->level]++;
			retval = TRUE;
		}
		else
		{
			results->missCount[cache->level]++;
			results->accessTotal[cache->level]++;
			retval = FALSE;
		}
	}
	return retval;
}

kickout addValueToCache(cache_s* cache, uint32 reference, opcode isWrite, results_s* results)
{
	uint32 assoc=0;
	kickout ret;
	switch(cache->level){
		case L1I:
		case L1D:
			assoc = L1_assoc;
			break;
		case L2:
			assoc = L2_assoc;
			break;
		default:
			printf("Invalid level\n");
			break;
	}
	if (assoc == 1)
	{
		if((ret=addValueToDMCache(cache,reference,isWrite)).type == CLEAN)
		{
			results->kickouts[cache->level]++;
		}
		else if(ret.type == DIRTY )
		{
			results->kickouts[cache->level]++;
			results->dirtykickouts[cache->level]++;
		}
	}
	else
	{
		if((ret=addValueToAssCache(cache,reference,isWrite)).type == CLEAN)
		{
			results->kickouts[cache->level]++;
		}
		else if(ret.type == DIRTY )
		{
			results->kickouts[cache->level]++;
			results->dirtykickouts[cache->level]++;
		}
	}
	return ret;
}
void printCache(cache_s* cache)
{
	uint32 assoc=0;


	switch(cache->level){
		case L1I:
			CPRINT(stderr,"\nMemory Level:  L1i\n");
			assoc = L1_assoc;
			break;
		case L1D:
			CPRINT(stderr,"\nMemory Level:  L1d\n");
			assoc = L1_assoc;
			break;
		case L2:
			CPRINT(stderr,"\nMemory Level:  L2\n");
			assoc = L2_assoc;
			break;
		default:
			printf("Invalid level\n");
			break;
	}

	if(assoc == 1)
	{
		printDMCache(cache);
	}
}
